import { Message } from 'element-ui'

// 生成唯一标识
function uuid() {
    var timestamp = (new Date()).getTime().toString(); // 当前时间戳
    var randomNum = Math.random().toString().substr(2, 9); // 随机数字字符串
    let num = (timestamp + randomNum) * 1;
    return num.toString(32).replace(/(0+)$/g, "");
}

function socketApi(parmars) {
    const { url, name, openSucceed, closedFn } = parmars;
    // 自定义名称
    this.name = name;
    // 是否开启
    this.isStart = false;
    // 连接状态
    this.status = 0;
    // 连接地址
    this.url = url;
    // socket唯一标识
    this.id = null;
    // 当前的socket实例
    this.socket = null;
    // 心跳时间
    this.heartbeatTime = 30000;
    // 断线重连时间
    this.againTime = 5000;
    // 心跳函数
    this.heartbeatFun = null;
    // 连接次数
    this.count = 0;
    // 消息返回函数
    this.messageBack = {};
    // 指定消息执行一次后将被删除
    this.backUuid = {};
    // 连接成功的回调
    this.openSucceed = openSucceed;
    // 短线之后的回调函数
    this.closedFn = closedFn;
    // 重连程序
    this.setTimeoutFun = null;
    // socket状态说明
    this.msg = '';
    // 设置断线之后的回调
    this.setclosedFn = fn => { if (typeof fn == 'function') this.closedFn = fn; }
    // 创建socket
    this.createSocket = () => {
        this.count++;
        // 生成唯一标识
        this.id = uuid();
        this.socket = new WebSocket(this.url);
        // console.log("启动连接:", this.url)
        // 启动监听
        this.initEvent();
    };
    // 初始化
    this.initSocket = () => {
        this.isStart = true;
        this.createSocket();
    };
    // 设置消息函数
    this.setMsgBack = resultBack => {
        // fun收到消息回调函数，funName函数名称，success设置成功后的回调函数
        const { fun, funName, success, cmd } = resultBack;
        if (typeof fun === 'function') {
            if (cmd && funName) {
                if (!this.messageBack[cmd]) {
                    this.messageBack[cmd] = {};
                } else {
                    // console.log(`指令${cmd}回调已存在`)
                    return;
                }
                if (this.messageBack[cmd][funName]) {
                    // console.log(`指令${cmd}下的${funName}回调已存在`)
                    return
                } else {
                    this.messageBack[cmd][funName] = fun;
                }
            } else if (cmd && !funName) {
                if (!this.messageBack[cmd]) {
                    this.messageBack[cmd] = fun;
                } else {
                    // console.log(`指令${cmd}回调已存在`)
                    return
                }
            } else if (!cmd && funName) {
                if (!this.messageBack[funName]) {
                    this.messageBack[funName] = fun;
                } else {
                    // console.log(`${funName}回调已存在`)
                    return
                }
            } else {
                // console.error("消息回调函数设置失败")
                return
            }
            if (success) success();
        } else {
            // console.error("fun 不是 function")
        }
    };
    // 设置唯一消息函数
    this.setMsgBackUuid = resultBack => {
        // fun收到消息回调函数，uuid函数唯一标识，success设置成功后的回调函数
        const { fun, uuid, success } = resultBack;
        if (typeof fun === 'function') {
            if (uuid) {
                this.backUuid[uuid] = fun;
                if (success) success();
            } else {
                console.error("唯一消息处理函数设置失败")
            }
        } else {
            console.error("fun 不是 function")
        }
    };
    // 初始化事件
    this.initEvent = () => {
        if (!this.socket) {
            console.log('socket未被创建');
            return;
        }
        this.socket.onopen = () => {
            this.status = 1;
            // console.log((this.name || this.id) + ":连接成功")
            // 重置连接次数
            this.count = 0;
            // 启动心跳
            // this.heartbeatFun = setInterval(() => { this.send('pong') }, this.heartbeatTime)
            // 执行连接成功后的回调函数
            if (this.openSucceed) this.openSucceed();
        }
        // 设置消息监听事件
        this.socket.onmessage = msg => {
            let data = null;
            try {
                // 如果是ArrayBuffer则转为字符串
                if (msg.data instanceof ArrayBuffer) {
                    // 假设 ArrayBuffer 对象为 buffer
                    const decoder = new TextDecoder('utf-8');
                    const text = decoder.decode(msg.data);
                    msg.data = text;
                }
                if (typeof msg.data == 'string') {
                    try {
                        data = JSON.parse(msg.data);
                    } catch (e) {
                        data = msg.data
                        Message.success(`${(this.name || this.url)}${data}`)
                    }
                }
                if (typeof msg.data == 'object') data = msg.data;
                // console.log((this.name || this.url) + "：收到消息：", data);
            } catch (e) {
                throw new Error("收到错误的消息：", msg)
            }
            // 如果存在uuid则执行
            if (data.uuid && this.backUuid[data.uuid]) {
                // console.log("进入唯一处理", data)
                this.backUuid[data.uuid](data);
                setTimeout(() => { delete this.backUuid[data.uuid]; }, 500)
                return;
            } else {
                if (!data.cmd) return
                if (data.cmd && this.messageBack[data.cmd]) {
                    const backMap = this.messageBack[data.cmd];
                    if (typeof backMap == 'function') {
                        backMap(data)
                    } else if (typeof backMap == 'object') {
                        for (let key in backMap) {
                            if (typeof backMap[key] === 'function') {
                                backMap[key](data);
                            }
                        }
                    }
                } else {
                    // console.log(data.cmd + "没有这个回调函数")
                    // console.log("收到消息：",data)
                }
            }
        }
        // 设置关闭事件
        this.socket.onclose = data => {
            this.status = 0;
            // 关闭心跳
            clearInterval(this.heartbeatFun);
            if (this.closedFn) this.closedFn();
            Message.error(`与${(this.name || this.url)}通信失败!   正在尝试重连`)
            // console.log(`与${(this.name || this.url)}通信失败!   正在尝试重连`)
            if (!this.isStart) {
                console.log(`与${(this.name || this.url)}连接已关闭`)
            } else {
                this.setTimeoutFun = setTimeout(() => {
                    console.log("重新连接：" + (this.name || this.url))
                    this.msg = (this.name || this.id) + "重新连接中...";
                    this.createSocket();
                }, this.againTime)
            }
        }
        // 设置错误事件
        this.socket.onerror = errMsg => {
            console.log(`与${(this.name || this.url)}:发生错误`, errMsg)
        }
    };
    // 发送唯一处理消息
    this.sendUuid = data => {
        return new Promise((resolve, reject) => {
            let id = uuid();
            if (data) { data.uuid = id; } else { data = { uuid: id } }
            this.setMsgBackUuid({
                fun: resolve,
                uuid: id,
                success: () => {
                    this.sendMsg(data, reject);
                }
            })
        })
    };
    // 单单发送消息
    this.sendMsg = (data) => {
        this.send({ data })
    };
    // 发送消息
    this.send = (obj, err) => {
        if (!this.socket) return;
        const { data } = obj;
        let msg = "";
        if (typeof data == "string") {
            msg = data;
        } else {
            msg = JSON.stringify(data);
        }
        this.socket.send(msg);

        // console.log((this.name || this.url) + "：发送消息：", data)
    };
    // 关闭socket
    this.close = () => {
        if (!this.socket) return;
        this.isStart = false;
        clearTimeout(this.setTimeoutFun);
        console.log(`已关闭${(this.name || this.url)}`)
        this.socket.close();
    };
    // 删除socket收到消息后的执行函数
    this.removeMsgBack = parmars => {
        const {cmd, funName} = parmars
        if (!cmd || !funName) {
            delete this.messageBack[cmd || funName];
            // console.log("已删除：" + cmd || funName + "回调函数");
        } else {
            delete this.messageBack[cmd][funName];
            // console.log("已删除：" + cmd + "下的" + funName + "回调函数");
        }
    };

    if (url) this.initSocket()
}

export default socketApi